/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package
///////////////

package org.apache.jena.util.iterator.test;

// Imports
///////////////
import junit.framework.*;

import java.util.*;

import org.apache.jena.rdf.model.*;
import org.apache.jena.util.*;
import org.apache.jena.vocabulary.RDFS;

/**
 * <p>
 * Unit tests on resource utilities
 * </p>
 */
public class TestResourceUtils extends TestCase {
    // Constants
    //////////////////////////////////

    public static final String NS = "http://jena.hp.com/test#";

    // Static variables
    //////////////////////////////////

    // Instance variables
    //////////////////////////////////

    // Constructors
    //////////////////////////////////

    public TestResourceUtils(String name) {
        super(name);
    }

    // External signature methods
    //////////////////////////////////

    public void testMaximalLowerElements() {
        Model m = ModelFactory.createDefaultModel();

        Resource a = m.createResource(NS + "a");
        Resource b = m.createResource(NS + "b");
        Resource c = m.createResource(NS + "c");
        Resource d = m.createResource(NS + "d");

        b.addProperty(RDFS.subClassOf, a);
        c.addProperty(RDFS.subClassOf, a);
        d.addProperty(RDFS.subClassOf, c);
        d.addProperty(RDFS.subClassOf, a);

        List<Resource> abcd = Arrays.asList(a, b, c, d);
        List<Resource> bcd = Arrays.asList(b, c, d);
        List<Resource> cd = Arrays.asList(c, d);

        assertEquals("Wrong number of remaining resources", 1, ResourceUtils.maximalLowerElements(abcd, RDFS.subClassOf, true).size());
        assertEquals("Result should be a", a, ResourceUtils.maximalLowerElements(abcd, RDFS.subClassOf, true).iterator().next());
        assertEquals("Wrong number of remaining resources", 2, ResourceUtils.maximalLowerElements(bcd, RDFS.subClassOf, true).size());
        assertEquals("Wrong number of remaining resources", 1, ResourceUtils.maximalLowerElements(cd, RDFS.subClassOf, true).size());
        assertEquals("Result should be a", c, ResourceUtils.maximalLowerElements(cd, RDFS.subClassOf, true).iterator().next());
    }

    public void testRenameResource() {
        testRenameResource(ModelFactory.createDefaultModel());
    }

    private void testRenameResource(Model m) {
        Resource a = m.createResource(NS + "a");
        Resource b = m.createResource(NS + "b");
        Resource c = m.createResource(NS + "c");
        Resource d = m.createResource(NS + "d");

        Property p = m.createProperty(NS, "p");
        Property q = m.createProperty(NS, "q");

        a.addProperty(p, b);
        a.addProperty(q, c);
        d.addProperty(p, a);
        d.addProperty(p, b);

        // now rename a to e
        Resource e = ResourceUtils.renameResource(a, NS + "e");

        assertTrue("should be no properties of a", !a.listProperties().hasNext());
        assertEquals("uri of a", NS + "a", a.getURI());
        assertEquals("uri of e", NS + "e", e.getURI());

        assertTrue("d should not have p a", !d.hasProperty(p, a));
        assertTrue("d should have p e", d.hasProperty(p, e));

        assertTrue("e should have p b", e.hasProperty(p, b));
        assertTrue("e should have q c", e.hasProperty(q, c));

        assertTrue("d p b should be unchanged", d.hasProperty(p, b));

        // now rename e to anon
        Resource anon = ResourceUtils.renameResource(e, null);

        assertTrue("should be no properties of e", !e.listProperties().hasNext());
        assertEquals("uri of e", NS + "e", e.getURI());
        assertTrue("anon", anon.isAnon());

        assertTrue("d should not have p e", !d.hasProperty(p, e));
        assertTrue("d should have p anon", d.hasProperty(p, anon));

        assertTrue("anon should have p b", anon.hasProperty(p, b));
        assertTrue("anon should have q c", anon.hasProperty(q, c));

        assertTrue("d p b should be unchanged", d.hasProperty(p, b));

        // reflexive case
        Resource f = m.createResource(NS + "f");
        f.addProperty(p, f);

        Resource f1 = ResourceUtils.renameResource(f, NS + "f1");
        assertFalse("Should be no f statements", m.listStatements(f, null, (RDFNode)null).hasNext());
        assertTrue("f1 has p f1", f1.hasProperty(p, f1));
    }

    public void testReachableGraphClosure() {
        Model m0 = ModelFactory.createDefaultModel();
        Resource a = m0.createResource("a");
        Resource b = m0.createResource("b");
        Resource c = m0.createResource("c");
        Resource d = m0.createResource("d");
        Property p = m0.createProperty("p");

        m0.add(a, p, b);
        m0.add(a, p, c);
        m0.add(b, p, b);  // unit loop
        m0.add(b, p, a);  // loop
        m0.add(d, p, a);  // not reachable from a

        Model m1 = ModelFactory.createDefaultModel();
        m1.add(a, p, b);
        m1.add(a, p, c);
        m1.add(b, p, b);
        m1.add(b, p, a);

        assertTrue("m1 should be isomorphic with the reachable sub-graph from a", m1.isIsomorphicWith(ResourceUtils.reachableClosure(a)));
    }

    public void testRemoveEquiv() {
        Model m = ModelFactory.createDefaultModel();

        Resource a = m.createResource(NS + "a");
        Resource b = m.createResource(NS + "b");
        Resource c = m.createResource(NS + "c");
        Resource d = m.createResource(NS + "d");
        Resource e = m.createResource(NS + "e");

        b.addProperty(RDFS.subClassOf, a);
        a.addProperty(RDFS.subClassOf, b);  // a,b are equivalent
        d.addProperty(RDFS.subClassOf, e);
        e.addProperty(RDFS.subClassOf, d);  // d,e are equivalent

        // reflexive relations - would be inferred by inf engine
        a.addProperty(RDFS.subClassOf, a);
        b.addProperty(RDFS.subClassOf, b);
        c.addProperty(RDFS.subClassOf, c);
        d.addProperty(RDFS.subClassOf, d);
        e.addProperty(RDFS.subClassOf, e);

        List<Resource> abcde = Arrays.asList(a, b, c, d, e);
        List<Resource> ab = Arrays.asList(a, b);
        List<Resource> cde = Arrays.asList(c, d, e);
        List<Resource> abde = Arrays.asList(a, b, d, e);
        List<Resource> de = Arrays.asList(d, e);

        List<Resource> in = new ArrayList<>();
        in.addAll(abcde);
        List<Resource> out = null;
        assertTrue(in.equals(abcde));
        assertFalse(in.equals(abde));
        assertFalse(in.equals(cde));
        assertNull(out);

        out = ResourceUtils.removeEquiv(in, RDFS.subClassOf, a);

        assertFalse(in.equals(abcde));
        assertFalse(in.equals(abde));
        assertTrue(in.equals(cde));
        assertNotNull(out);
        assertEquals(out, ab);

        out = ResourceUtils.removeEquiv(in, RDFS.subClassOf, e);

        assertFalse(in.equals(abcde));
        assertFalse(in.equals(abde));
        assertTrue(in.equals(Collections.singletonList(c)));
        assertNotNull(out);
        assertEquals(out, de);
    }

    public void testPartition() {
        Model m = ModelFactory.createDefaultModel();

        Resource a = m.createResource(NS + "a");
        Resource b = m.createResource(NS + "b");
        Resource c = m.createResource(NS + "c");
        Resource d = m.createResource(NS + "d");
        Resource e = m.createResource(NS + "e");

        b.addProperty(RDFS.subClassOf, a);
        a.addProperty(RDFS.subClassOf, b);  // a,b are equivalent
        d.addProperty(RDFS.subClassOf, e);
        e.addProperty(RDFS.subClassOf, d);  // d,e are equivalent

        // reflexive relations - would be inferred by inf engine
        a.addProperty(RDFS.subClassOf, a);
        b.addProperty(RDFS.subClassOf, b);
        c.addProperty(RDFS.subClassOf, c);
        d.addProperty(RDFS.subClassOf, d);
        e.addProperty(RDFS.subClassOf, e);

        List<Resource> abcde = Arrays.asList(new Resource[]{a, b, c, d, e});
        List<Resource> ab = Arrays.asList(new Resource[]{b, a});
        List<Resource> cc = Arrays.asList(new Resource[]{c});
        List<Resource> de = Arrays.asList(new Resource[]{e, d});

        List<List<Resource>> partition = ResourceUtils.partition(abcde, RDFS.subClassOf);
        assertEquals("Should be 3 partitions", 3, partition.size());
        assertEquals("First parition should be (a,b)", ab, partition.get(0));
        assertEquals("First parition should be (c)", cc, partition.get(1));
        assertEquals("First parition should be (d,e)", de, partition.get(2));
    }

    // Internal implementation methods
    //////////////////////////////////

    // ==============================================================================
    // Inner class definitions
    // ==============================================================================

}
